package com.gitee.wsl.compose.ui.contextmenu

import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.size
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.MenuItemColors
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.gitee.wsl.common.ui.base.Padding
import com.gitee.wsl.compose.ui.base.Text
import com.gitee.wsl.compose.ui.text.Cupertino


/**
 * @author Vivien Mahe
 * @since 01/04/2024
 */
@Composable
fun ContextMenu(
    modifier: Modifier = Modifier,
    shown: Boolean = true,
    onDismiss: (() -> Unit)? = null,
    textStyle: TextStyle = LocalTextStyle.current,
    fontWeight: FontWeight? = null,
    colors: ContextMenuColors = ContextMenuDefaults.colors(),
    sizes: ContextMenuSizes = ContextMenuDefaults.sizes(),
    items: List<ContextMenuItemModel>,
    onItemClick: ((ContextMenuItemModel) -> Unit)? = null,
) {
    AdaptiveContextMenu(
        modifier = modifier,
        shown = shown,
        onDismiss = onDismiss,
        textStyle = textStyle,
        fontWeight = fontWeight,
        sizes = sizes,
        items = items,
        onItemClick = onItemClick,
        adaptation = {
            material {
                this.colors = MenuDefaults.itemColors(
                    textColor = colors.contentColor(),
                    disabledTextColor = colors.disabledContentColor(),
                    leadingIconColor = colors.contentColor(),
                    disabledLeadingIconColor = colors.disabledContentColor(),
                )
            }
        },
    )
}

@Composable
private fun AdaptiveContextMenu(
    modifier: Modifier = Modifier,
    shown: Boolean = true,
    onDismiss: (() -> Unit)? = null,
    textStyle: TextStyle = LocalTextStyle.current,
    fontWeight: FontWeight? = null,
    sizes: ContextMenuSizes = ContextMenuDefaults.sizes(),
    adaptation: AdaptationScope<CupertinoContextMenuAdaptation, MaterialContextMenuAdaptation>.() -> Unit = {},
    items: List<ContextMenuItemModel>,
    onItemClick: ((ContextMenuItemModel) -> Unit)? = null,
) {
    AdaptiveWidget(
        adaptation = remember { ContextMenuAdaptation() },
        adaptationScope = adaptation,
        material = {
            DropdownMenu(
                modifier = modifier,
                expanded = shown,
                onDismissRequest = { onDismiss?.invoke() },
            ) {
                items.forEach { item ->
                    DropdownMenuItem(
                        modifier = Modifier,
                        text = { Text(text = item.title, style = textStyle, fontWeight = fontWeight) },
                        enabled = item.enabled,
                        colors = it.colors,
                        leadingIcon = item.icon?.let { imageVector ->
                            {
                                Icon(
                                    modifier = Modifier.size(sizes.iconsSize()),
                                    imageVector = imageVector,
                                    contentDescription = "",
                                    //tint =  it.colors.,
                                )
                            }
                        },
                        onClick = { onItemClick?.invoke(item) },
                    )
                }
            }
        },
        cupertino = {
            CupertinoDropdownMenu(
                modifier = modifier,
                expanded = shown,
                elevation = 6.dp,
                paddingValues = PaddingValues(Padding.ExtraSmall),
                onDismissRequest = { onDismiss?.invoke() },
            ) {
                items.forEach { item ->
                    MenuAction(
                        contentColor = it.colors.contentColor(enabled = item.enabled).value,
                        enabled = item.enabled,
                        icon = {
                            item.icon?.let { imageVector ->
                                Icon(
                                    modifier = Modifier.size(sizes.iconsSize()),
                                    imageVector = imageVector,
                                    contentDescription = null,
                                    tint = it.colors.contentColor(item.enabled).value,
                                )
                            }
                        },
                        onClick = { onItemClick?.invoke(item) },
                    ) {
                        Text.Cupertino(
                            text = item.title,
                            style = textStyle,
                            fontWeight = fontWeight,
                        )
                    }
                }
            }
        },
    )
}

@Stable
class CupertinoContextMenuAdaptation internal constructor(
    var colors: CupertinoMenuItemColors
)

@Stable
class MaterialContextMenuAdaptation internal constructor(
    var colors: MenuItemColors
)


@Stable
private class ContextMenuAdaptation :
    Adaptation<CupertinoContextMenuAdaptation, MaterialContextMenuAdaptation>() {

    @Composable
    override fun rememberCupertinoAdaptation(): CupertinoContextMenuAdaptation {

        val colors = CupertinoMenuContextDefaults.colors()

        return remember(colors) {
            CupertinoContextMenuAdaptation(colors = colors)
        }
    }

    @Composable
    override fun rememberMaterialAdaptation(): MaterialContextMenuAdaptation {

        val colors = MenuDefaults.itemColors()

        return remember(colors) {
            MaterialContextMenuAdaptation(colors = colors)
        }
    }
}

object ContextMenuDefaults {

    val IconsSize = 24.dp

    @Composable
    fun colors(
        contentColor: Color = MaterialTheme.colorScheme.onSurface,
        disabledContentColor: Color = MaterialTheme.colorScheme.outline,
        dividerColor: Color = MaterialTheme.colorScheme.outline,
    ): ContextMenuColors = ContextMenuColors(
        contentColor = contentColor,
        disabledContentColor = disabledContentColor,
        dividerColor = dividerColor,
    )

    @Composable
    fun sizes(
        iconsSize: Dp = IconsSize,
    ): ContextMenuSizes = ContextMenuSizes(
        iconsSize = iconsSize,
    )
}

@Immutable
class ContextMenuColors internal constructor(
    private val contentColor: Color,
    private val disabledContentColor: Color,
    private val dividerColor: Color,
) {
    @Composable
    internal fun contentColor(): Color = contentColor

    @Composable
    internal fun disabledContentColor(): Color = disabledContentColor

    @Composable
    internal fun dividerColor(): Color = dividerColor
}

@Immutable
class ContextMenuSizes internal constructor(
    private val iconsSize: Dp,
) {
    @Composable
    internal fun iconsSize(): Dp = iconsSize
}

@Composable
fun AdaptiveWidget(
    material : @Composable () -> Unit,
    cupertino : @Composable () -> Unit
) {
    /*when(LocalTheme.current){
        Theme.Cupertino -> cupertino()
        else -> material()
    }*/
    return material()
}

@Composable
fun <C,M> AdaptiveWidget(
    adaptation : Adaptation<C, M>,
    material : @Composable (M) -> Unit,
    cupertino : @Composable (C) -> Unit,
    adaptationScope : AdaptationScope<C, M>.() -> Unit,
) {
    adaptation.adaptationScope()

    return material(adaptation.rememberUpdatedMaterialAdaptation())

}

/**
 * Scope for customizing [material] and [cupertino] specs of the widget.
 *
 * Custom adaptive widgets can be created using [AdaptiveWidget] composable with implemented [Adaptation]
 *
 * @see AdaptiveWidget
 * @see Adaptation
 * */
@Stable
sealed interface AdaptationScope<C,M> {

    /**
     * Customize properties that are exclusive for Cupertino widget or have different default value
     *
     * @param block customization block
     * */
    fun cupertino(block: @Composable C.() -> Unit)

    /**
     * Customize properties that are exclusive for Material widget or have different default value
     *
     * @param block customization block
     * */
    fun material(block: @Composable M.() -> Unit)
}



@Stable
abstract class Adaptation<C, M> : AdaptationScope<C,M> {

    private var cupertino: @Composable C.() -> Unit by mutableStateOf({})

    private var material: @Composable M.() -> Unit by mutableStateOf({})

    override fun cupertino(block: @Composable C.() -> Unit) {
        cupertino = block
    }

    override fun material(block: @Composable M.() -> Unit) {
        material = block
    }

    /**
     * Create and remember initial cupertino adaptation state
     * */
    @Composable
    protected abstract fun rememberCupertinoAdaptation(): C

    /**
     * Create and remember initial material adaptation state
     * */
    @Composable
    protected abstract fun rememberMaterialAdaptation(): M

    @Composable
    internal fun rememberUpdatedCupertinoAdaptation(): C {
        return key(cupertino) {
            rememberCupertinoAdaptation().apply { cupertino() }
        }
    }

    @Composable
    internal fun rememberUpdatedMaterialAdaptation(): M {
        return key(material) {
            rememberMaterialAdaptation().apply { material() }
        }
    }
}